package com.yxh.lib_base.util.router

import android.os.Bundle
import android.content.Intent
import android.os.Parcelable
import android.content.ComponentName
import android.content.ActivityNotFoundException
import android.app.Activity
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import java.io.Serializable
import java.util.ArrayList
import java.util.HashMap

/**
 * 实现 Activity 路由跳转，只在 TUICore 内部使用，不对外暴露
 */
class RouterImpl private constructor() {
    fun setDestination(path: String?): Navigation {
        val navigation = Navigation()
        navigation.setDestination(path)
        return navigation
    }

    class Navigation {
        var destination: String? = null
        var options: Bundle? = null
        var intent: Intent? = Intent()
        fun setOptions(options: Bundle?): Navigation {
            this.options = options
            return this
        }

        fun putExtra(key: String?, value: Boolean): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Byte): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Char): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Short): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Int): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Long): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Float): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: Double): Navigation {
            intent!!.putExtra(key, value)
            return this
        }

        fun putExtra(key: String?, value: String?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: CharSequence?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: Parcelable?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: Array<Parcelable?>?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: Serializable?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: BooleanArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: ByteArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: ShortArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: CharArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: IntArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: LongArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: FloatArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: DoubleArray?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: Array<String?>?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: Array<CharSequence?>?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtra(key: String?, value: Bundle?): Navigation {
            if (value != null) {
                intent!!.putExtra(key, value)
            }
            return this
        }

        fun putExtras(bundle: Bundle?): Navigation {
            if (bundle != null) {
                intent!!.putExtras(bundle)
            }
            return this
        }

        fun putExtras(src: Intent?): Navigation {
            if (src != null) {
                intent!!.putExtras(src)
            }
            return this
        }

        fun setDestination(path: String?): Navigation {
            destination = routerMap[path]
            if (destination == null) {
                Log.e(TAG, "destination is null.")
                return this
            }
            intent!!.component = ComponentName(context!!, destination!!)
            return this
        }

        fun setIntent(intent: Intent?): Navigation {
            this.intent = intent
            return this
        }

        // 使用传入的 Fragment 启动 Activity，并返回接收返回结果
        // 使用传入的 Fragment 启动 Activity
        @JvmOverloads
        fun navigate(fragment: Fragment?, requestCode: Int = -1) {
            if (!initialized) {
                Log.e(TAG, "have not initialized.")
                return
            }
            if (intent == null) {
                Log.e(TAG, "intent is null.")
                return
            }
            try {
                if (fragment != null) {
                    if (requestCode >= 0) {
                        fragment.startActivityForResult(intent!!, requestCode)
                    } else {
                        fragment.startActivity(intent!!, options)
                    }
                } else {
                    startActivity(null, requestCode)
                }
            } catch (e: ActivityNotFoundException) {
                e.printStackTrace()
            }
        }

        // 使用传入的 Context 启动 Activity，并返回接收返回结果
        // 使用传入的 Context 启动 Activity
        // 使用默认的 ApplicationContext 启动 Activity
        @JvmOverloads
        fun navigate(context: Context? = null as Context?, requestCode: Int = -1) {
            if (!initialized) {
                Log.e(TAG, "have not initialized.")
                return
            }
            if (intent == null) {
                Log.e(TAG, "intent is null.")
                return
            }
            var startContext = context
            if (context == null) {
                startContext = Companion.context
            }
            startActivity(startContext, requestCode)
        }

        private fun startActivity(context: Context?, requestCode: Int) {
            if (context == null) {
                Log.e(TAG, "StartActivity failed, context is null.Please init")
                return
            }
            try {
                if (context is Activity && requestCode >= 0) {
                    ActivityCompat.startActivityForResult(
                        (context as Activity?)!!,
                        intent!!,
                        requestCode,
                        options
                    )
                } else {
                    if (context !is Activity) {
                        intent!!.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    }
                    ActivityCompat.startActivity(context, intent!!, options)
                }
            } catch (e: ActivityNotFoundException) {
                e.printStackTrace()
            }
        }
    }

    companion object {
        private val TAG = RouterImpl::class.java.simpleName
        val instance = RouterImpl()
        private val routerMap: MutableMap<String?, String> = HashMap()
        var context: Context? = null
            private set
        private var initialized = false
        @Synchronized
        fun init(context: Context?) {
            if (initialized) {
                return
            }
            Companion.context = context
            if (context == null) {
                Log.e(TAG, "init failed, context is null.")
                return
            }
            initRouter(context)
            initialized = true
        }

        fun initRouter(context: Context) {
            var activityInfos: Array<ActivityInfo>? = null
            val activityNames: MutableList<String> = ArrayList()
            val packageManager = context.packageManager
            try {
                val packageInfo = packageManager.getPackageInfo(
                    context.packageName,
                    PackageManager.GET_ACTIVITIES
                )
                activityInfos = packageInfo.activities
            } catch (e: PackageManager.NameNotFoundException) {
                e.printStackTrace()
            }
            if (activityInfos != null) {
                for (activityInfo in activityInfos) {
                    activityNames.add(activityInfo.name)
                }
            }
            for (activityName in activityNames) {
                val splitStr = activityName.split("\\.".toRegex()).toTypedArray()
                routerMap[splitStr[splitStr.size - 1]] = activityName
            }
        }
    }
}